# Dreams have to come true after all
import json
import random
from flask import g
from flask import current_app, request
from flask_limiter.util import get_remote_address
from flask_restful import Resource
from flask_restful.reqparse import RequestParser  # 对请求参数进行验证

from comment.models import db
from comment.models.user import User
from comment.models.index import Category
from comment.util.huyi_sms import send_sms
from comment.util.limiter import limiter as lmt
from comment.util.parse import mobile, regex
from comment.util.shopping_redis import redis_client
from . import constants
import comment.util.parse

from comment.util.tokens_pyjwt import generate_tokens, verify_tokens
from comment.util.decorators import login_required


# 我们定义测试的资源类
class Shopping_User(Resource):
    """
    在get函数上加上登录的拦截
    """
    # 固定的属性名
    method_decorators = {
        'get': [login_required],
        'post': [login_required]
    }

    def get(self):  # 测试：当前get函数必须让用户登录之后才能访问
        current_app.logger.info('我的测试日志')
        # 这里的代码可能会用到User模型类
        return {'hello': '测试'}
    # def post(self):
    #     return {'hello': 'post 测试'}
    #
    # def put(self):
    #     return {'hello': 'put 测试'}


class User_SMS(Resource):
    error_message = 'Tom many requests.'
    decorators = [  # 装饰器
        # 三个参数：参数1：限流的速率,参数2：key_func,参数3：如果超出限制之后的提示信息
        lmt.limit(constants.LIMIT_SMS_CODE_BY_MOBILE,
                  key_func=lambda: request.args['phone'],
                  error_message=error_message),
        lmt.limit(constants.LIMIT_SMS_CODE_BY_IP,
                  key_func=get_remote_address,
                  error_message=error_message)
    ]

    def get(self):
        phone = request.args.get('phone').strip()
        code = random.randint(1000, 9999)  # 随机获取在范围之间的数
        result = (send_sms.send_sms_code(phone, str(code)))  # 把int格式的字符串变换为字典
        # result往里面添加手机号码
        result['phone'] = phone
        # 短信验证码发送成功之后，还需要把验证码存放到redis数据库中，以便于下次验证，验证码的时效为5分钟
        redis_client.setex('shopping:code:{}'.format(phone), constants.SMS_CODE_EXPIRES, code)  # 参数1：key,参数2：时效

        return result


class AuthorizationCodeResource(Resource):
    """
    对redis数据库中保存的验证码进行验证
    """

    def post(self):
        rp = RequestParser()
        rp.add_argument('phone', type=mobile, required=True)
        rp.add_argument('code', type=regex(r'^\d{4}'), required=True)
        args = rp.parse_args()
        phone = args.phone
        code = args.code
        # 从redis获取数据库中保存的验证码
        key = 'shopping:code:{}'.format(phone)
        print('-----')
        try:
            real_code = redis_client.get(key)
            current_app.logger.error(real_code)
        except ConnectionError as  e:
            current_app.logger.error(e)
            return {'message': 'redis db connect error.'}, 400
        # 开始校验
        if not real_code or real_code.decode() != code:
            return {'message': 'Invalid code'}, 400
        return {'phone': phone, 'msg': 'code success'}


class RegisterUserResource(Resource):
    '''
    填写账号信息
    '''

    def post(self):
        rp = RequestParser()
        rp.add_argument('phone', type=mobile, required=True)
        rp.add_argument('username', required=True)
        rp.add_argument('password', required=True)
        rp.add_argument('email', type=comment.util.parse.email, required=True)
        args = rp.parse_args()
        username = args.username
        password = args.password
        phone = args.phone
        email = args.email

        # 验证用户名是否唯一 :先从mysql数据库中根据当前用户名查询
        u = User.query.filter(User.username == username).first()
        if u:  # 用户名已经存在
            current_app.logger.info('{}:用户名已经存在，请换一个'.format(username))
            return {'msg': 'The username already exists.'}, 400

        # 把用户信息保存到数据库中
        u = User(username=username, pwd=password, email=email, phone=phone, status=0)
        db.session.add(u)
        db.session.commit()
        return {'msg': 'ok'}


class UserLoginResource(Resource):
    """
    登录
    """

    def post(self):
        #
        '''
        request.form.get("key", type=str, default=None) 获取表单数据，
        但在post请求下，request.form无法获取有效参数
        request.args.get("key") 获取get请求参数，
        request.values.get("key") 获取所有参数。
        推荐使用request.values.get().
        :return:
        '''

        username = request.values.get('username')
        password = request.values.get('password')
        # print(username, password)
        # all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE，如果是返回 True，否则返回 False。
        if not all([username, password]):
            return {'message': '数据不完整'}
        '''
        利用User对象从数据库获取用户信息
        '''
        user = User.query.filter(User.username == username).first()
        if user:  # 如果不为空,说明用户存在
            # 调用User类里的check_password方法
            if user.check_password(password):
                # 必须把登录成功之后的用户 ID得到token，token返回给前端
                token = generate_tokens(user.id)
                current_app.logger.info(verify_tokens(token))
                return {'msg': 'Login Success.', 'token': token}, 200
                # return {'msg': 'Login Success.'}
        return {'message': '用户名或者密码错误.'}


class IsExistPhoneResource(Resource):
    '''
    判断手机号是否存在
    '''

    def post(self):
        phone = request.values.get('phone')
        user = User.query.filter(User.phone == phone).first()
        if user:
            return {'isExist': True, 'message': '此手机号已注销', 'code': 203}
        else:
            return {'isExist': False, 'message': '此手机号可注册', 'code': 200}


class UserLoginOutResource(Resource):
    '''
    退出登录
    '''

    def post(self):
        if g.user_id:
            g.user_id = None
        return {'msg': '退出登录'}

    pass
